/*
  * @(#)ColladaAnimTest.java 0.5 08/12/04
  *
  * Copyright 2008 100town.com. All rights reserved.
  * Use is subject to license terms.
*/
package ImplSample;

import java.awt.BorderLayout;
import java.awt.DisplayMode;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;

import org.collada._2005._11.colladaschema.Animation;
import org.collada.model.Action;
import org.collada.model.Model;
import org.collada.anim.ModelControl;
import org.collada.util.model.RendableModel;
import org.collada.util.ColladaLoader;
import org.collada.util.action.ActionUtil;
import org.collada.anim.RunningType;
import com.sun.opengl.util.Animator;

public class ColladaAnimTest implements GLEventListener {
	String filePath = "src/ImplSample/model1.xml";
	Model model;

    public static void main(String[] args) {
        JFrame frame = new JFrame("COLLADA Loader Test");
        frame.getContentPane().setLayout(new BorderLayout());

        GLCanvas canvas = new GLCanvas();
        final ColladaAnimTest demo = new ColladaAnimTest();
        canvas.addGLEventListener(demo);
        frame.getContentPane().add(canvas, BorderLayout.CENTER);

        DisplayMode mode = GraphicsEnvironment.getLocalGraphicsEnvironment()
                .getDefaultScreenDevice().getDisplayMode();

        frame.setSize((int) (0.15f * mode.getWidth()), (int) (0.15f * mode
                .getHeight()));

        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                // Run this on another thread than the AWT event queue to
                // make sure the call to Animator.stop() completes before
                // exiting
                new Thread(new Runnable() {
                    public void run() {
                        System.exit(0);
                    }
                }).start();
            }
        });
        frame.setVisible(true);
    }

    private GLU glu = new GLU();

    ColladaLoader colladaLoader = new ColladaLoader(){
    	public Object load(Model model){
    		System.out.println("//TODO: load dae:" + model.getURI());
    		if(model.getGeometry()!=null){
    			List<Double> geomValues = model.getGeometry().getValues();
    			if(geomValues!=null && geomValues.size()>0){
    				for(double D: geomValues){
        				System.out.println("dd" + D);
        			}
    			}
    		}
    		//Test Animations
    		Animation animation = new Animation();
    		animation.setName("animationID1");
    		animation.setId("animationID1");
    		model.getAnimations().add(animation);
    		//Test Animations end
    		return model;
    	}
    	public Object toRenderable(final Model model){
    		RendableModel rendableModel = new RendableModel(model){
    			Map<String, Animation> mapAnimation = new HashMap<String, Animation>();
    			public Map<String, Animation> getMapAnimation(){
    				return mapAnimation;
    			}
    			public void putMapAnimation(Animation anim){
    				mapAnimation.put(anim.getId(), anim);
    			}
    			public void toMapAnimation(){
    				if(model.getAnimations()!=null && model.getAnimations().size()>0){
    					for(Animation anim: model.getAnimations()){
    						putMapAnimation(anim);
    					}
    				}
    			}
    			public void update(){
    				//System.out.println("current time : " + time);
    				if(model.getControls()!=null && model.getControls().size()>0){
    					for(ModelControl control: model.getControls()){
    						if(control.isActive()){
    							System.out.println("updating one active control" + control);
    							//TODO: for run_once action, it should be determine by if the key time > keyEndTime
    							if(control.getRunningType()==RunningType.ONCE){
    								control.setActive(false);
    							}
    							//TODO: same reasons as above
    							if(control.getRunningType()==RunningType.LIMITED_REPEAT){
    								System.out.println("left repeat" + control.getRepeatTimes());
    								if(control.getRepeatTimes()>0){
    									control.setRepeatTimes(control.getRepeatTimes()-1);
    								}else{
    									control.setActive(false);
    								}
    							}
    						}
    					}
    				}
    			}
    			public void render(){
    				//System.out.println("I am rendering!");
    			}
    		};
    		rendableModel.toMapAnimation();
    		List<ModelControl> controls = rendableModel.getModel().getControls();
    		if(controls!=null && controls.size()>0){
    			for(ModelControl modelControl: controls){
    				List<String> animationIDs = modelControl.getAnimationIDs();
    				if(animationIDs!=null && animationIDs.size()>0){
    					for(String animationID: animationIDs){
    						for(Animation animation: model.getAnimations()){
    							if(animation.getId()!=null && animation.getId().equals(animationID)){
    								System.out.println("catch " + animationID);
    								//TODO: set start time, end time, time step
    								modelControl.setKeyStartTime(0.0);
    								modelControl.setKeyEndTime(0.99);
    								modelControl.setTimeStep(0.03);
    								//End TODO:
    								break;
    							}
    						}
    					}
    				}
    				List<Action> actions = rendableModel.getModel().getActions();
    				if(actions!=null && actions.size()>0){
    					for(Action action: actions){
    						action.setModelControl(modelControl);
    						if(action.getActionListenerClasses()!=null && action.getActionListenerClasses().size()>0){
    							for(Class<Object> actionListenerClasses: action.getActionListenerClasses()){
    								try{
    									//Object listener = Class.forName(actionListenerClasses).newInstance();
    									Object listener = actionListenerClasses.newInstance();
    									if(listener instanceof ActionListener){
    										action.getActionListeners().add((ActionListener)listener);
    									}else{
    										throw new IllegalArgumentException(actionListenerClasses.getName() + listener);
    									}
    								}catch(Exception ee){
    									ee.printStackTrace();
    								}
    							}
    						}
    					}
    				}
    			}
    		}
    		return rendableModel;
    	}
    };
	public void init(GLAutoDrawable drawable) {
        File cfile = new File(filePath);
		model = ColladaLoader.unmarshal(cfile);
		model.setLoaded(colladaLoader.load(model));
		RendableModel rendableModel = (RendableModel)(colladaLoader.toRenderable(model));
		drawable.addKeyListener(ActionUtil.toKeyListener(rendableModel.getSwitchCameraAction()));
		drawable.addKeyListener(ActionUtil.toKeyListener(rendableModel.getSwitchBackCameraAction()));
		List<ModelControl> controls = rendableModel.getModel().getControls();
		if(controls!=null && controls.size()>0){
			List<Action> actions = model.getActions();
			if(actions!=null && actions.size()>0){
				for(Action action: actions){
					drawable.addKeyListener(ActionUtil.toKeyListener(action));
				}
			}
		}
		model.setRenderable(rendableModel);
		Animator animator = new Animator(drawable);
		animator.start();
    }
    public void display(GLAutoDrawable drawable) {
        GL gl = drawable.getGL();
        gl.glClear(GL.GL_COLOR_BUFFER_BIT);
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluOrtho2D(0, drawable.getWidth(), 0, drawable.getHeight());
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
        if(model.getRenderable()!=null && (model.getRenderable() instanceof RendableModel)){
        	//Ideally, the update process can be done multiple thread
        	((RendableModel)model.getRenderable()).update();
        	((RendableModel)model.getRenderable()).render();
        }
    }
    int width;
    int height;
    public void reshape(GLAutoDrawable drawable, int x, int y, int width,
            int height) {
        this.width = width;
        this.height = height;
    }

    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged,
            boolean deviceChanged) {
    }
}
